<template>
  <section class="cloud-bed">
    <div class="cloud-box">
      <div
          v-for="(item, index) in dataList"
          :key="index"
          @click="getDataInfo(item)"
          :style="[{background:item.bgColor}, item.style]"
      >
        {{ item.name }}
      </div>
    </div>
  </section>

</template>

<script setup lang="ts">
import {defineComponent, nextTick, onBeforeUnmount, onMounted, ref} from "vue";

const timer = ref(50) // 球体转动速率
const radius = ref(0) // 词云球体面积大小
const dtr = ref(Math.PI / 180)//鼠标滑过球体转动速度
const active = ref(false) // 默认加载是否开启转动
const lasta = ref(0.2) // 上下转动
const lastb = ref(0.2) // 左右转动
const distr = ref(true)
const tspeed = ref(0) // 鼠标移动上去时球体转动
const mouseX = ref(0)
const mouseY = ref(0)
const tagAttrList = ref<any[]>([])
const tagContent = ref<any>(null)
const cloudContent = ref<any>(null)
const sinA = ref<any>('')
const cosA = ref<any>('')
const sinB = ref<any>('')
const cosB = ref<any>('')
const sinC = ref<any>('')
const cosC = ref<any>('')
const setTimer = ref<any>(null)
const dataList = ref<Record<string, any>[]>([
  {
    name: '火灾数据',
    value: '10',
    style: 'width: 118px; height: 118px',
    bgColor: 'rgb(57, 193, 207,0.12)',
    color: '#39c1cf',
  },
  {
    name: '警情数据',
    value: '10',
    style: 'width: 146px; height: 146px',
    bgColor: 'rgb(66, 105, 245,0.12)',
    color: '#4269f5',
  },
  {
    name: '消控室数据',
    value: '10',
    style: 'width: 118px; height: 118px',
    bgColor: 'rgb(184, 107, 215,0.12)',
    color: '#b86bd7',
  },
  {
    name: '人员数据',
    value: '10',
    style: 'width: 98px; height: 98px',
    bgColor: 'rgb(243, 84, 83,0.12)',
    color: '#f35453',
  },
  {
    name: '单位数据',
    value: '10',
    style: 'width: 98px; height: 98px',
    bgColor: 'rgb(250, 116, 20,0.12)',
    color: '#FA7414',
  },
  {
    name: '监督数据',
    value: '10',
    style: 'width: 98px; height: 98px',
    bgColor: 'rgb(255, 171, 30,0.12)',
    color: '#FFAB1E',
  },
  {
    name: '巡查数据',
    value: '10',
    style: 'width: 98px; height: 98px',
    bgColor: 'rgb(136, 104, 217,0.12)',
    color: '#8868D9',
  }
])

function getDataInfo(item: any) {
  console.log(item, 'item')
}

function initWordCloud() {
  cloudContent.value = document.querySelector('.cloud-box') as HTMLElement;
  tagContent.value = cloudContent.value.getElementsByTagName('div');
  for (let i = 0; i < tagContent.value.length; i++) {
    let tagObj = { offsetWidth: 0, offsetHeight: 0};
    tagObj.offsetWidth = tagContent.value[i].offsetWidth;
    tagObj.offsetHeight = tagContent.value[i].offsetHeight;
    tagAttrList.value.push(tagObj);
  }
  sineCosine(0, 0, 0);
  positionAll();
  setTimer.value = setInterval(() => update(), timer.value);
}

function positionAll() {
  let phi = 0;
  let theta = 0;
  let max = tagAttrList.value.length;
  let aTmp = [];
  let oFragment = document.createDocumentFragment();
  //随机排序
  for (let i = 0; i < tagContent.value.length; i++) {
    aTmp.push(tagContent.value[i]);
  }
  aTmp.sort(() => {
    return Math.random() < 0.5 ? 1 : -1;
  });
  for (let i = 0; i < aTmp.length; i++) {
    oFragment.appendChild(aTmp[i]);
  }
  cloudContent.value.appendChild(oFragment);
  for (let i = 1; i < max + 1; i++) {
    if (distr) {
      phi = Math.acos(-1 + (2 * i - 1) / max);
      theta = Math.sqrt(max * Math.PI) * phi;
    } else {
      phi = Math.random() * (Math.PI);
      theta = Math.random() * (2 * Math.PI);
    }
    //坐标变换
    tagAttrList.value[i - 1].cx = radius.value * Math.cos(theta) * Math.sin(phi) * 0.7;
    tagAttrList.value[i - 1].cy = radius.value * Math.sin(theta) * Math.sin(phi) * 0.2;
    tagAttrList.value[i - 1].cz = radius.value * Math.cos(phi);
    tagContent.value[i - 1].style.left = tagAttrList.value[i - 1].cx + cloudContent.value.offsetWidth / 2 - tagAttrList.value[i - 1].offsetWidth / 2 + 'px';
    tagContent.value[i - 1].style.top = tagAttrList.value[i - 1].cy + cloudContent.value.offsetHeight / 2 - tagAttrList.value[i - 1].offsetHeight / 2 + 'px';
  }
}

function update() {
  let angleBasicA;
  let angleBasicB;

  if (active.value) {
    angleBasicA = (-Math.min(Math.max(-mouseY, -200), 200) / radius.value) * tspeed.value;
    angleBasicB = (Math.min(Math.max(-mouseX, -200), 200) / radius.value) * tspeed.value;
  } else {
    angleBasicA = lasta.value * 0.98;
    angleBasicB = lastb.value * 0.98;
  }

  sineCosine(angleBasicA, angleBasicB, 0);
  for (let j = 0; j < tagAttrList.value.length; j++) {
    let rx1 = tagAttrList.value[j].cx;
    let ry1 = tagAttrList.value[j].cy * cosA.value + tagAttrList.value[j].cz * (-sinA.value);
    let rz1 = tagAttrList.value[j].cy * sinA.value + tagAttrList.value[j].cz * cosA.value;

    let rx2 = rx1 * cosB.value + rz1 * sinB.value;
    let ry2 = ry1;
    let rz2 = rx1 * (-sinB.value) + rz1 * cosB.value;

    let rx3 = rx2 * cosC.value + ry2 * (-sinC.value);
    let ry3 = rx2 * sinC.value + ry2 * cosC.value;
    let rz3 = rz2;
    tagAttrList.value[j].cx = rx3;
    tagAttrList.value[j].cy = ry3;
    tagAttrList.value[j].cz = rz3;

    let per = 350 / (350 + rz3);

    tagAttrList.value[j].x = rx3 * per - 2;
    tagAttrList.value[j].y = ry3 * per;
    tagAttrList.value[j].scale = per;
    tagAttrList.value[j].alpha = per;

    tagAttrList.value[j].alpha = (tagAttrList.value[j].alpha - 0.6) * (10 / 6);
  }
  doPosition();
  depthSort();
}

function doPosition() {
  let len = cloudContent.value.offsetWidth / 2;
  let height = cloudContent.value.offsetHeight / 2;
  for (let i = 0; i < tagAttrList.value.length; i++) {
    tagContent.value[i].style.left = tagAttrList.value[i].cx + len - tagAttrList.value[i].offsetWidth / 2 + 'px';
    tagContent.value[i].style.top = tagAttrList.value[i].cy + height - tagAttrList.value[i].offsetHeight / 2 + 'px';
    tagContent.value[i].style.fontSize = Math.ceil(12 * tagAttrList.value[i].scale/2) + 8 + 'px';
    tagContent.value[i].style.fontSize = Math.ceil(12 * tagAttrList.value[i].scale / 2) + 2 + 'px';
    // tagContent.value[i].style.filter = "alpha(opacity=" + 100 * tagAttrList.value[i].alpha + ")";
    // tagContent.value[i].style.opacity = tagAttrList.value[i].alpha;
  }
}

function depthSort() {
  let aTmp = [];
  for (let i = 0; i < tagContent.value.length; i++) {
    aTmp.push(tagContent.value[i]);
  }
  aTmp.sort((item1, item2) => item2.cz - item1.cz);
  for (let i = 0; i < aTmp.length; i++) {
    aTmp[i].style.zIndex = i;
  }
}

function sineCosine(a: number, b: number, c: number) {
  sinA.value = Math.sin(a * dtr.value);
  cosA.value = Math.cos(a * dtr.value);
  sinB.value = Math.sin(b * dtr.value);
  cosB.value = Math.cos(b * dtr.value);
  sinC.value = Math.sin(c * dtr.value);
  cosC.value = Math.cos(c * dtr.value);
}


onMounted(() => {
  nextTick(() => {
    const box = document.querySelector('.cloud-box') as HTMLElement
    radius.value = box?.offsetWidth / 2
    initWordCloud()
  })
})

onBeforeUnmount(() => {
  if(setTimer.value) {
    clearInterval(setTimer.value)
    setTimer.value = null
  }
})

defineComponent({name: 'WordCloud'})
</script>

<style scoped lang="scss">
.cloud-bed {
  width: 100%;
  height: 100%;
  margin: auto;
}

.cloud-box {
  position: relative;
  margin: 20px auto 0px;
  width: 100%;
  height: 100%;
  background: #00000000;
}

.cloud-box div {
  position: absolute;
  padding: 3px 6px;
  top: 0px;
  font-weight: bold;
  text-decoration: none;
  left: 0px;
  background-image: linear-gradient(red, #fff);
  background-clip: text;
  color: transparent;
  border-radius: 50%;
  text-align: center;
  color: #fff;

  display: flex;
  align-items: center;
  justify-content: center;

  /* line-height: 50px;
  overflow:hidden;
  white-space: nowrap;
  text-overflow: ellipsis; */
}
</style>